import requests
import json
import os


class DingTalkSender:
    def __init__(self, access_token):
        self.access_token = access_token
        self.base_url = "https://oapi.dingtalk.com"
        # 验证token有效性
        self._validate_token()

    def _validate_token(self):
        """验证access_token是否有效"""
        url = f"{self.base_url}/robot/getWebhookCallback?access_token={self.access_token}"
        try:
            response = requests.get(url)
            result = response.json()
            if result.get("errcode") != 0:
                print(f"⚠️ 警告：access_token可能无效 - {result.get('errmsg')}")
        except Exception as e:
            print(f"验证token时出错: {str(e)}")

    def send_text_message(self, message):
        """发送文本消息"""
        url = f"{self.base_url}/robot/send?access_token={self.access_token}"

        headers = {
            "Content-Type": "application/json;charset=utf-8"
        }

        data = {
            "msgtype": "text",
            "text": {
                "content": message
            }
        }

        try:
            response = requests.post(
                url=url,
                headers=headers,
                data=json.dumps(data)
            )

            result = response.json()
            if result.get("errcode") == 0:
                print("✅ 文本消息发送成功")
                return True
            else:
                print(f"❌ 文本消息发送失败: {result.get('errmsg')}")
                self._handle_common_errors(result.get("errcode"))
                return False
        except Exception as e:
            print(f"发送过程出错: {str(e)}")
            return False

    def upload_media(self, file_path):
        """上传文件到钉钉服务器"""
        if not os.path.exists(file_path):
            print(f"❌ 文件不存在: {file_path}")
            return None

        if not os.path.isfile(file_path):
            print(f"❌ 不是有效的文件: {file_path}")
            return None

        file_size = os.path.getsize(file_path)
        if file_size > 20 * 1024 * 1024:  # 20MB限制
            print(f"❌ 文件过大（{file_size / 1024 / 1024:.2f}MB），超过20MB限制")
            return None

        url = f"{self.base_url}/media/upload?access_token={self.access_token}&type=file"

        try:
            with open(file_path, 'rb') as f:
                files = {
                    'media': (os.path.basename(file_path), f)
                }
                response = requests.post(url, files=files)

                result = response.json()
                if result.get("errcode") == 0:
                    print("✅ 文件上传成功")
                    return result.get("media_id")
                else:
                    print(f"❌ 文件上传失败: {result.get('errmsg')}")
                    self._handle_common_errors(result.get("errcode"))
                    return None
        except Exception as e:
            print(f"文件上传出错: {str(e)}")
            return None

    def send_file_message(self, file_path, title=""):
        """发送文件消息"""
        # 先上传文件获取media_id
        media_id = self.upload_media(file_path)
        if not media_id:
            return False

        url = f"{self.base_url}/robot/send?access_token={self.access_token}"

        headers = {
            "Content-Type": "application/json;charset=utf-8"
        }

        # 如果没有提供标题，使用文件名作为标题
        if not title:
            title = os.path.basename(file_path)

        data = {
            "msgtype": "file",
            "file": {
                "media_id": media_id,
                "title": title
            }
        }

        try:
            response = requests.post(
                url=url,
                headers=headers,
                data=json.dumps(data)
            )

            result = response.json()
            if result.get("errcode") == 0:
                print("✅ 文件消息发送成功")
                return True
            else:
                print(f"❌ 文件消息发送失败: {result.get('errmsg')}")
                self._handle_common_errors(result.get("errcode"))
                return False
        except Exception as e:
            print(f"发送过程出错: {str(e)}")
            return False

    def _handle_common_errors(self, error_code):
        """处理常见错误码"""
        error_handlers = {
            40014: "access_token无效，请检查并重新获取",
            42001: "access_token已过期，请重新获取",
            40003: "机器人不存在或已被删除，请重新创建机器人"
        }

        if error_code in error_handlers:
            print(f"💡 解决方案: {error_handlers[error_code]}")


if __name__ == "__main__":
    # 替换为你的钉钉机器人access_token
    # https: // oapi.dingtalk.com / robot / send?access_token =
    # cfb6365e5bbab5b1d911e5497e38b80fd43a57b7c5f3d791bf1cb68f66425dd9
    # ACCESS_TOKEN = "请替换为你的有效access_token"
    # https: // oapi.dingtalk.com / robot / send?access_token = \
        # ee8dba3164f8300190d8bcfd1c06caaa7da75f8c2cdcfe7bf126d952ccbabaf5
    ACCESS_TOKEN = "9193fe3c88c5ca08e65c44fb2a3f2a1de8e132bf37ef56101a0ff85e01447b8d"

    # 创建发送器实例
    sender = DingTalkSender(ACCESS_TOKEN)

    # 发送文本消息
    sender.send_text_message("这是一条测试文本消息！忽略掉")

    # 发送文件（替换为你的文件路径）
    file_path = "1.txt"  # 可以是任意类型的文件
    sender.send_file_message(file_path, title="测试文件")

    """  可以发送消息，但是发送文件失败
    ❌ 文件上传失败: 不合法的access_token
💡 解决方案: access_token无效，请检查并重新获取
    """
